package com.orange.base.core.util;

import java.sql.Clob;
import java.sql.Date;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.cursor.Cursor;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.github.pagehelper.PageRowBounds;

/**
 * Mybatis工具类
 * 
 * @author wlwang
 *
 */
@Component
public final class MybatisUtil {

    private static final String EXECUTE_SQL_ID = "com.orange.base.core.util.mapping.MybatisUtilMapper.executeQuerySql";

    private static SqlSessionTemplate sqlSessionTemplate;

    public static SqlSessionTemplate getSqlSessionTemplate() {
        return sqlSessionTemplate;
    }

    @Autowired
    public void setSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        MybatisUtil.sqlSessionTemplate = sqlSessionTemplate;
    }

    private MybatisUtil() {
    }

    /**
     * 通过id查询数据
     * 
     * @param mapper
     * @param params 参数
     * @return
     * @throws Exception
     */
    public static <T> List<T> selectList(String mapper, Object params) throws Exception {
        List<T> datas = sqlSessionTemplate.selectList(mapper, params);
        changeType(datas);
        return datas;
    }

    /**
     * 
     * 查询分页数据
     * 
     * @param mapper
     * @param params参数
     * @param page分页信息
     * @return
     * @throws Exception
     */
    public static <T> List<T> selectList(String mapper, Object params, PageRowBounds page) throws Exception {
        List<T> datas = sqlSessionTemplate.selectList(mapper, params, page);
        changeType(datas);
        return datas;
    }

    /**
     * 执行传过来的sql语句
     * 
     * @param sql
     * @param params参数
     * @param page分页信息
     * @return
     * @throws Exception
     */
    public static List<Map<String, Object>> executeQuerySql(String sql, Object[] params, PageRowBounds page) throws Exception {
        Map<String, Object> param = new HashMap<String, Object>(16);
        String executeSql = convertMybatisSql(sql, params, param);
        param.put("sql", executeSql);
        List<Map<String, Object>> datas = sqlSessionTemplate.selectList(EXECUTE_SQL_ID, param, page);
        changeType(datas);
        return datas;
    }

    /**
     * 执行传过来的sql语句用游标查询
     * 
     * @param sql
     * @param params
     * @param page
     * @return
     * @throws Exception
     */
    public static <T> Cursor<T> executeQuerySqlCursor(String sql, Object[] params, PageRowBounds page) throws Exception {
        Map<String, Object> param = new HashMap<String, Object>(16);
        String executeSql = convertMybatisSql(sql, params, param);
        param.put("sql", executeSql);
        return sqlSessionTemplate.selectCursor(EXECUTE_SQL_ID, param, page);
    }

    /**
     * 将普通sql转换mybatissql
     * 
     * @param sql
     * @param params
     * @param param
     * @return
     */
    public static String convertMybatisSql(String sql, Object[] params, Map<String, Object> param) throws Exception {
        if (params == null) {
            return null;
        }
        int count = StringUtils.countMatches(sql, "?");
        if (count != params.length) {
            throw new RuntimeException("SQL占位符和参数个数不等，请检查.sql:" + sql + ";param:" + StringUtils.join(params, ","));
        }
        StringBuilder sb = new StringBuilder();
        char[] chars = sql.toCharArray();
        int index = 0;
        for (char c : chars) {
            if (c == '?') {
                String key = "KEY_" + index;
                sb.append("#{").append(key).append("}");
                param.put(key, params[index]);
                index++;
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 判断id是否存在
     * 
     * @param id
     * @return
     * @throws Exception
     */
    public static boolean idIsExists(String id) throws Exception {
        Collection<String> mapper = sqlSessionTemplate.getConfiguration().getMappedStatementNames();
        Iterator<String> iter = mapper.iterator();
        while (iter.hasNext()) {
            String mapperId = iter.next();
            if (mapperId.equals(id)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 修改mybatis返回结果类型
     * 
     * @param <T>
     * 
     * @param datas转换的数据
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    private static <T> void changeType(List<T> datas) throws Exception {
        if (datas == null || datas.isEmpty()) {
            return;
        }
        for (Object data : datas) {
            if (data instanceof Map) {
                Map<String, Object> map = (Map<String, Object>) data;
                Iterator<Entry<String, Object>> iter = map.entrySet().iterator();
                while (iter.hasNext()) {
                    Entry<String, Object> entry = iter.next();
                    String key = entry.getKey();
                    Object value = entry.getValue();
                    if (value instanceof Clob) {
                        Clob clob = (Clob) value;
                        String clobString = clob.getSubString(0, (int) clob.length());
                        map.put(key, clobString);
                    } else if (value instanceof Timestamp) {
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        map.put(key, sdf.format(value));
                    } else if (value instanceof Date) {
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        map.put(key, sdf.format(value));
                    }
                }
            }

        }
    }

}
